#include "stdafx.h"

#include "App.h"
#include "MGUI_Input.h"


App * App::msInstance = NULL;

App::App()
	: mEditorMode(EM_None)
{
	msInstance = this;

	mInst = NULL;
	mWnd = NULL;

	mCursor = NULL;
}

App::~App()
{
	msInstance = NULL;
}

bool App::Init()
{
	mSystem = new System();
	mCursor = new Cursor;

	RECT rect;
	GetClientRect(mWnd, &rect);
	DWORD iWidth = rect.right - rect.left;
	DWORD iHeight = rect.bottom - rect.top;

	mSystem->Init();

	mRenderSystem = new GLRenderSystem(mWnd);
	mUIEngine = new MGUI_Engine(iWidth, iHeight);

	mMainFrame = new MainFrame;

	mMainFrame->Layout();

	return true;
}

void App::Update()
{
	System::Instance()->Run();

	mUIEngine->Update();

	mRenderSystem->BeginScene();

	mRenderSystem->Clear(0xFF000000);

	mUIEngine->Render();

	mRenderSystem->EndScene();
}

void App::Shutdown()
{ 
	delete mMainFrame;

	delete mUIEngine;

	delete mCursor;

	delete mRenderSystem;

	mSystem->Shutdown();
	delete mSystem;
}

bool App::Quit()
{
	return false;
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMsg,WPARAM wParam,LPARAM lParam) 
{ 
	switch(iMsg)
	{
	case WM_CREATE:
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		break;

	case WM_SETCURSOR:
		Cursor::Instance()->Draw();
		break;

	case WM_LBUTTONDOWN:
		if (MGUI_InputManager::Instance())
		{
			int x = LOWORD(lParam);
			int y = HIWORD(lParam);

			MGUI_InputManager::Instance()->_injectMousePressed(x, y, MGUI_MouseButton::Left);
		}
		break;

	case WM_LBUTTONUP:
		if (MGUI_InputManager::Instance())
		{
			int x = LOWORD(lParam);
			int y = HIWORD(lParam);

			MGUI_InputManager::Instance()->_injectMouseReleased(x, y, MGUI_MouseButton::Left);
		}
		break;

	case WM_RBUTTONDOWN:
		if (MGUI_InputManager::Instance())
		{
			int x = LOWORD(lParam);
			int y = HIWORD(lParam);

			MGUI_InputManager::Instance()->_injectMousePressed(x, y, MGUI_MouseButton::Right);
		}
		break;

	case WM_RBUTTONUP:
		if (MGUI_InputManager::Instance())
		{
			int x = LOWORD(lParam);
			int y = HIWORD(lParam);

			MGUI_InputManager::Instance()->_injectMouseReleased(x, y, MGUI_MouseButton::Right);
		}
		break;

	case WM_MOUSEMOVE:
		if (MGUI_InputManager::Instance())
		{
			int x = LOWORD(lParam);
			int y = HIWORD(lParam);

			MGUI_InputManager::Instance()->_injectMouseMove(x, y);
		}
		break;

	case WM_KEYDOWN:
		{
			bool repeat = (lParam & (1 >> 30)) != 0;
			if (!repeat)
			{
				int scan_code = MGUI_Input::VirtualKeyToScanCode(wParam);
				int text = MGUI_Input::VirtualKeyToText(wParam);

				MGUI_InputManager::Instance()->_injectKeyPressed(MGUI_KeyCode::Enum(scan_code), (MGUI_Char)text);
			}
		}
		break;

	case WM_KEYUP:
		{
			int scan_code = MGUI_Input::VirtualKeyToScanCode(wParam);
			MGUI_KeyCode code = MGUI_KeyCode::Enum(scan_code);

			MGUI_InputManager::Instance()->_injectKeyReleased(code);
		}
		break;

	case WM_IME_CHAR:
		{
			int text = 0;
#ifdef _UNICODE
			text = wParam;
#else
			char mbstr[3];
			BYTE hiByte = wParam >> 8;
			BYTE loByte = wParam & 0x000000FF;
			if (hiByte == 0)
			{
				mbstr[0] = loByte;
				mbstr[1] = '\0';
			}
			else
			{
				mbstr[0] = hiByte;
				mbstr[1] = loByte;
				mbstr[2] = '\0';
			}

			wchar_t wstr[2];
			/*int num = */MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mbstr, -1, wstr, _countof(wstr));
			text = wstr[0];
#endif // _UNICODE

			MGUI_InputManager::Instance()->_injectKeyPressed(MGUI_KeyCode::None, (MGUI_Char)text);
		}
		break;

	case WM_SIZE:
		if (wParam != SIZE_MINIMIZED)
		{
			RECT rc;

			GetClientRect(hWnd, &rc);

			int w = rc.right - rc.left;
			int h = rc.bottom - rc.top;

			if (App::Instance())
				App::Instance()->Resize(w, h);
		}
		break;

	default:
		break;
	}

	return ::DefWindowProc(hWnd, iMsg, wParam, lParam); 
}

static const char * WIN32_CLASS_NAME = "UIEditor";

void App::Run(HINSTANCE hInstance)
{
	mInst = hInstance;

	WNDCLASS wc;
	wc.cbClsExtra = 0; 
	wc.cbWndExtra = 0; 
	wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.hCursor = NULL; 
	wc.hIcon = LoadIcon(hInstance, IDI_WINLOGO); 
	wc.hInstance = hInstance; 
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = WIN32_CLASS_NAME; 
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW | CS_VREDRAW;

	TCHAR tile[128] = "UIEditor";
	DWORD style = WS_OVERLAPPEDWINDOW;
	POINT pt = { CW_USEDEFAULT, CW_USEDEFAULT };
	SIZE sz = { CW_USEDEFAULT, CW_USEDEFAULT };

	RegisterClass(&wc);

	mWnd = CreateWindow(WIN32_CLASS_NAME, tile, style, 
		pt.x, pt.y, sz.cx, sz.cy,
		NULL, NULL, hInstance, NULL);

	if (Init())
	{
		ShowWindow(mWnd, SW_SHOW);

		MSG msg;
		memset(&msg,0,sizeof(msg));
		while(msg.message != WM_QUIT && !Quit())
		{
			if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
			else
			{
				Update();
				::Sleep(10);
			}
		}

		Shutdown();
	}

	UnregisterClass(WIN32_CLASS_NAME, hInstance);
}

void App::Resize(int w, int h)
{
	RECT rect;
	GetClientRect(mWnd, &rect);
	DWORD width = rect.right - rect.left;
	DWORD height = rect.bottom - rect.top;

	mRenderSystem->OnResize(width, height);
	mUIEngine->OnResize(width, height);

	mMainFrame->Layout();
}

void App::SetEditorMode(eEditorMode mode)
{
	if (mEditorMode != mode)
	{
		mEditorMode = mode;
		eventEditorModeChanged(mode);
	}
}

eEditorMode App::GetEditorMode()
{
	return mEditorMode;
}